﻿using DevExpress.Spreadsheet;
using DevExpress.Spreadsheet.Export;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Forms;
using XCI.Core;
using XCI.Helper;
using XCI.Windows;

namespace XCI.Excel
{
    /// <summary>
    /// DevExpress实现的Excel的导入导出
    /// </summary>
    public class ExcelData
    {
        public const string ExcelFilter = "Excel2007文件 (*.xlsx)|*.xlsx|Excel2003文件 (*.xls)|*.xls|Excel文件 (*.xlsx;*.xls)|*.xlsx;*.xls";

        /// <summary>
        /// 从Excel文件中导入数据到DataTable
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <param name="firstRowIsHeader">首行是否是列头</param>
        public virtual DataTable Import(string filePath, bool firstRowIsHeader)
        {
            try
            {
                Workbook book = new Workbook();
                book.LoadDocument(filePath);
                var sheet = book.Worksheets[0];
                var range = sheet.Cells.CurrentRegion;
                DataTable table = sheet.CreateDataTable(range, firstRowIsHeader);
                DataTableExporter exporter = sheet.CreateDataTableExporter(range, table, firstRowIsHeader);
                exporter.Export();
                return table;
            }
            catch (Exception ex)
            {
                throw new ExcelException($"导入Excel出错:{ex.Message}", ex);
            }
        }

        /// <summary>
        /// 导入Excel文件
        /// </summary>
        /// <param name="filePath">文件读取路径</param>
        /// <param name="firstRowIsHeader">首行是否是列头</param>
        public virtual List<T> Import<T>(string filePath, bool firstRowIsHeader) where T : class, new()
        {
            var table = Import(filePath, firstRowIsHeader);
            return ApiModelManager.ConvertExportDataTableToObjectList(table, () => new T());
        }

        /// <summary>
        /// 打开导入文件对话框选择文件后执行导入回调函数
        /// </summary>
        /// <param name="callback">导入回调函数</param>
        /// <param name="loadingMaskOwner">加载面板容器,如果为空则不显示</param>
        public virtual async Task ImportFileDialogAsync(ExportImportCallback callback, Control loadingMaskOwner = null)
        {
            if (callback == null) throw new ExcelException("请指定Excel导入回调函数");
            var openFileDialog = new OpenFileDialog
            {
                AddExtension = true,
                DefaultExt = "xlsx",
                Filter = ExcelData.ExcelFilter
            };
            if (openFileDialog.ShowDialog() != DialogResult.OK)
            {
                openFileDialog.Dispose();
                return;
            }

            LoadingMask loadingMask = null;
            if (loadingMaskOwner != null) loadingMask = new LoadingMask(loadingMaskOwner);
            try
            {
                loadingMask?.Show();
                await callback.Invoke(openFileDialog.FileName);
                loadingMask?.Hide();
            }
            catch (Exception ex)
            {
                MessageBoxHelper.ShowError($"导入时出错:{ex.Message}");
            }
            finally
            {
                loadingMask?.Hide();
            }
            openFileDialog.Dispose();
        }

        /// <summary>
        /// DataTable对象集合到Excel的多个Sheet中
        /// </summary>
        /// <param name="list">DataTable对象集合</param>
        public virtual byte[] Export(IEnumerable<ExportDataTable> list)
        {
            Workbook workbook = new Workbook();
            var index = 0;
            foreach (var item in list)
            {
                Worksheet sheet = index == 0 ? workbook.Worksheets[0] : workbook.Worksheets.Add();
                sheet.Name = item.SheetName;
                sheet.Import(item.Table, true, 0, 0);
                sheet.Columns.AutoFit(0, sheet.Cells.CurrentRegion.ColumnCount - 1);
                index++;
            }

            workbook.Sheets.ActiveSheet = workbook.Sheets[0];
            return workbook.SaveDocument(DocumentFormat.Xlsx);
        }

        /// <summary>
        /// 把DataTable中的数据导出到Excel文件流中
        /// </summary>
        /// <param name="filePath">文件写入路径</param>
        /// <param name="list">对象集合</param>
        /// <param name="sheetName">输出的Excel中Sheet名称</param>
        public virtual BoolResult Export<T>(string filePath, List<T> list, string sheetName) where T : class
        {
            var table = ApiModelManager.ConvertExportObjectListToDataTable(list);
            var bytes = Export(new List<ExportDataTable> { new ExportDataTable { Table = table, SheetName = sheetName } });
            return IOHelper.WriteFile(bytes, filePath);
        }

        /// <summary>
        /// 把DataTable中的数据导出到Excel文件流中
        /// </summary>
        /// <param name="filePath">文件写入路径</param>
        /// <param name="table">DataTable对象</param>
        /// <param name="sheetName">输出的Excel中Sheet名称</param>
        public virtual BoolResult Export(string filePath, DataTable table, string sheetName)
        {
            var bytes = Export(new List<ExportDataTable> { new ExportDataTable { Table = table, SheetName = sheetName } });
            return IOHelper.WriteFile(bytes, filePath);
        }

        /// <summary>
        /// 把DataTable中的数据导出到Excel文件流中
        /// </summary>
        /// <param name="filePath">文件写入路径</param>
        /// <param name="tables">DataTable对象集合</param>
        public virtual BoolResult Export(string filePath, params ExportDataTable[] tables)
        {
            var bytes = Export(tables);
            return IOHelper.WriteFile(bytes, filePath);
        }

        /// <summary>
        /// 打开导出文件对话框后执行导出回调函数
        /// </summary>
        /// <param name="callback">导出回调函数</param>
        /// <param name="defaultName">默认文件名称</param>
        /// <param name="loadingMaskOwner">加载面板容器,如果为空则不显示</param>
        /// <param name="effectiveExportFields">导出字段数组,如果不为空则显示列选择窗体,否则直接进行导出回调</param>
        public virtual async Task ExportFileDialogAsync(ExportExportCallback callback, string defaultName, Control loadingMaskOwner = null, string[] effectiveExportFields=null)
        {
            if (callback == null) throw new ExcelException("请指定Excel导出回调函数");
            var result = ExportSelectFields(effectiveExportFields);
            if (result.Fail) return;

            var fileSave = new SaveFileDialog
            {
                AddExtension = true,
                DefaultExt = "xlsx",
                FileName = $"{defaultName}.xlsx",
                Filter = ExcelData.ExcelFilter
            };
            if (fileSave.ShowDialog() != DialogResult.OK)
            {
                fileSave.Dispose();
                return;
            }

            LoadingMask loadingMask = null;
            if (loadingMaskOwner != null) loadingMask = new LoadingMask(loadingMaskOwner);
            try
            {
                loadingMask?.Show();
                await callback.Invoke(fileSave.FileName, result.Data);
                loadingMask?.Hide();
                if (DialogResult.Yes == MessageBoxHelper.ShowMessageYesNo("导出成功，现在要打开吗？"))
                {
                    try
                    {
                        Process.Start(fileSave.FileName);
                    }
                    catch
                    {
                        // ignored
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBoxHelper.ShowError($"导出时出错:{ex.Message}");
            }
            finally
            {
                loadingMask?.Hide();
            }

            fileSave.Dispose();
        }

        private BoolResult<string[]> ExportSelectFields(string[] effectiveExportFields)
        {
            if (effectiveExportFields == null || effectiveExportFields.Length == 0)
            {
                return new BoolResult<string[]>(true);
            }

            string[] exportFields = null;
            bool isSelected = false;
            var frm = new FrmExportSelectFields(effectiveExportFields, true);
            if (frm.ShowDialog() == DialogResult.OK)
            {
                exportFields = frm.GetSelectedFields();
                isSelected = true;
            }
            frm.Dispose();
            return new BoolResult<string[]>(isSelected, exportFields);
        }
    }

    public class ExportDataTable
    {
        /// <summary>
        /// Excel表Sheet名称
        /// </summary>
        public string SheetName { get; set; }

        /// <summary>
        /// 数据对象
        /// </summary>
        public DataTable Table { get; set; }
    }

    public delegate Task ExportImportCallback(string filePath);
    public delegate Task ExportExportCallback(string filePath, string[] exportFields);

    /// <summary>
    /// Excel异常
    /// </summary>
    public class ExcelException : Exception
    {
        public ExcelException()
        {

        }

        public ExcelException(string message) : base(message)
        {

        }

        public ExcelException(string message, Exception innerException) : base(message, innerException)
        {

        }
    }
}